package org

import (
	"bytes"
	"context"
	"errors"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/dto/base"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/repository/base/area"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/repository/base/org"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/repository/base/profit"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils/ossfile"
	basePb "git.mycaigou.com/gfyx/micro-gfyx-api/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/base"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/xuri/excelize/v2"
	"net/http"
	"strconv"
	"strings"
)

type OrgService struct {
	orgRepo    org.OrgRepositoryIface
	areaRepo   area.AreaRepositoryIface
	profitRepo profit.ProfitRepositoryIface
}

// 构造函数
func NewOrgService(orgRepo org.OrgRepositoryIface, areaRepo area.AreaRepositoryIface, profitRepo profit.ProfitRepositoryIface) OrgServiceIface {
	return &OrgService{
		orgRepo:    orgRepo,
		areaRepo:   areaRepo,
		profitRepo: profitRepo,
	}
}

// 新增或更新组织
func (s *OrgService) OrgSave(ctx context.Context, orgObj *base.OrgItem) (int64, error) {
	return s.orgRepo.OrgSave(ctx, orgObj)
}

// 删除组织
func (s *OrgService) OrgDelete(ctx context.Context, param *base.OrgDeleteParams) (int64, error) {
	return s.orgRepo.OrgDelete(ctx, param)
}

// 组织列表
func (s *OrgService) OrgList(ctx context.Context) ([]*base.OrgItem, error) {
	return s.orgRepo.OrgList(ctx)
}

// 导入组织数据
func (s *OrgService) OrgImport(ctx context.Context, param *base.OrgImportParam) (*base.OrgImportResponse, error) {
	fileUrl, err := ossfile.GetSignURL(param.FilePath)
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport-ossfile.GetSignURL fail, err:%+v", err)
		return nil, err
	}
	stark.Logger.Infof(ctx, "OrgImport oss file:%s", fileUrl)
	rowDatas, err := s.readRemoteExcelData(ctx, fileUrl)
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport-readRemoteExcelData fail, err:%+v", err)
		return nil, err
	}
	// 数据校验&格式转换
	orgList, errMsgList, cellErrFlag, err := s.execlDataToOrgData(ctx, rowDatas)
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport-execlDataToOrgData err:", err)
		return nil, err
	}
	resp := &base.OrgImportResponse{}
	// 字段&格式错误标注
	stark.Logger.Infof(ctx, "execlDataToOrgData:", errMsgList, cellErrFlag)
	if cellErrFlag && errMsgList != nil && len(errMsgList) > 0 {
		newFileurl, err := s.addImportOrgDataFormatComment(ctx, errMsgList, fileUrl)
		if err != nil {
			stark.Logger.Errorf(ctx, "OrgImport-addImportOrgDataFormatComment fail, err:%+v", err)
			return nil, err
		}
		stark.Logger.Infof(ctx, "file url:%s", newFileurl)
		// response
		resp.FilePath = newFileurl
		resp.SuccessRowsNum = 0
		resp.FailRowsNum = int64(len(rowDatas) - 3)
		return resp, nil
	}

	// 写入错误信息&上传Oss
	importMsgList, err := s.orgRepo.OrgImport(ctx, orgList)
	if err != nil {
		stark.Logger.Errorf(ctx, "导入组织信息失败：%v", err)
		return nil, err
	}
	if importMsgList != nil && len(importMsgList) > 0 {
		commentFileUrl, successNum, failNum, err := s.addImportOrgDataErrorComment(ctx, importMsgList, fileUrl)
		if err != nil {
			stark.Logger.Errorf(ctx, "OrgImport-addImportOrgDataErrorComment fail, err:%+v", err)
			return nil, err
		}
		resp.FilePath = commentFileUrl
		resp.SuccessRowsNum = successNum
		resp.FailRowsNum = failNum
		return resp, nil
	}

	return nil, errors.New("导入失败")
}

func (s *OrgService) readRemoteExcelData(ctx context.Context, fileDownloadUrl string) ([][]string, error) {
	var rowData [][]string
	if fileDownloadUrl == "" {
		return rowData, nil
	}

	resp, err := http.Get(fileDownloadUrl)
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport ossfile download 失败：%s", err)
		return rowData, err
	}

	f, err := excelize.OpenReader(resp.Body)
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport excelize open 失败：%s", err)
		return rowData, errors.New("导入文件格式错误")
	}
	defer func() {
		if err = f.Close(); err != nil {
			stark.Logger.Errorf(ctx, "OrgImport excelize close 失败：%s", err)
		}
		if err = resp.Body.Close(); err != nil {
			stark.Logger.Errorf(ctx, "OrgImport ossfile download close 失败：%s", err)
		}
	}()

	rowData, err = f.GetRows("组织架构导入模板")
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgImport excelize read rows 失败：%s", err)
		return rowData, err
	}

	return rowData, nil
}

func (s *OrgService) execlDataToOrgData(ctx context.Context, rows [][]string) ([]*base.OrgImportItem, [][]string, bool, error) {
	cellErrFlag := false

	if len(rows) == 0 {
		return nil, nil, cellErrFlag, errors.New("导入文件内容为空")
	}
	if len(rows) <= 3 {
		return nil, nil, cellErrFlag, errors.New("导入文件内容为空")
	}
	errMsgList := [][]string{}
	orgList := make([]*base.OrgImportItem, 0)
	for i, row := range rows {
		if i >= 3 {
			// 导入数据开始
			// 最大列数
			maxColLen := 2
			//检查导入数据内容&格式
			rowMsg := make([]string, 2)
			for k, val := range row {
				val = strings.TrimSpace(val)
				if k < 1 { //小于模板必填字段数
					msg := ""
					if val == "" {
						msg = "内容不能为空"
					}
					if msg != "" {
						cellErrFlag = true
					}
					rowMsg[k] = msg
				}
			}

			errMsgList = append(errMsgList, rowMsg)
			if len(row) > 0 {
				orgItem := &base.OrgImportItem{
					OrgFullName: strings.TrimSpace(row[0]),
				}
				if len(row) >= maxColLen {
					orgItem.AreaNames = strings.TrimSpace(row[1])
				}
				orgList = append(orgList, orgItem)
			}
		} else {
			// 模板内容
			if i == 2 { //校验模板是否正确
				templateRows := []string{"组织全称", "关联区域"}
				for k, template := range templateRows {
					if row[k] != template {
						return nil, nil, cellErrFlag, errors.New("模板格式错误")
					}
				}
			}
		}
	}

	return orgList, errMsgList, cellErrFlag, nil
}

func (s *OrgService) addImportOrgDataErrorComment(ctx context.Context, msgList []*basePb.ImportOrgMsg, fileDownloadUrl string) (string, int64, int64, error) {
	if len(msgList) == 0 {
		stark.Logger.Errorf(ctx, "组织导入返回信息为空")
		return "", 0, 0, errors.New("导入失败")
	}
	successNum := 0
	failNum := 0
	errMsgList := [][]string{}
	for _, msg := range msgList {
		if msg.IsSuccess {
			successNum += 1
		} else {
			failNum += 1
		}

		errMsg := []string{
			0: msg.OrgFullName,
			1: msg.AreaNames,
		}
		errMsgList = append(errMsgList, errMsg)
	}
	// 没有失败信息不返回批注文档
	if len(errMsgList) > 0 {
		newFileUrl, err := s.addImportOrgDataFormatComment(ctx, errMsgList, fileDownloadUrl)
		if err != nil {
			return "", int64(successNum), int64(failNum), err
		}
		return newFileUrl, int64(successNum), int64(failNum), nil
	}

	return "", int64(successNum), int64(failNum), nil
}

func (s *OrgService) addImportOrgDataFormatComment(ctx context.Context, errMsgList [][]string, fileDownloadUrl string) (string, error) {
	resp, err := http.Get(fileDownloadUrl)
	if err != nil {
		stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment ossfile download 失败：%s", err)
		return "", err
	}

	f, err := excelize.OpenReader(resp.Body)

	defer func() {
		if err = f.Close(); err != nil {
			stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment excelize close 失败：%s", err)
		}
		if err = resp.Body.Close(); err != nil {
			stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment ossfile download close 失败：%s", err)
		}
	}()

	for i, errMsg := range errMsgList {
		index := i + 4
		for k, val := range errMsg {
			if val == "" {
				continue
			}
			columnName := utils.IntToLetter(k)
			cellName := columnName + strconv.Itoa(index)

			err = f.AddComment("组织架构导入模板", excelize.Comment{
				Cell: cellName,
				Paragraph: []excelize.RichTextRun{
					{Text: val},
				},
			})
			if err != nil {
				stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment AddComment 失败：%s", err)
				return "", err
			}
		}
	}

	var updatedContent bytes.Buffer
	if err := f.Write(&updatedContent); err != nil {
		stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment-write fail, err:%+v", err)
		return "", err
	}

	tenantCode := "ycg" // 租户号，根据实际情况赋值
	fileExt := ".xlsx"  // 文件扩展类型，根据实际情况赋值
	filePath, _, err := ossfile.PutOssV2(bytes.NewReader(updatedContent.Bytes()), constants.PathUserOrganization, tenantCode, fileExt, 1)
	if err != nil {
		stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment-PutOssV2 fail, err:%+v", err)
		return "", err
	}

	newFileUrl, err := ossfile.GetSignURL(filePath)
	if err != nil {
		stark.Logger.Errorf(ctx, "addImportOrgDataFormatComment-GetSignURL fail, err:%+v", err)
		return "", err
	}

	return newFileUrl, nil
}

func (s *OrgService) AreaTrees(ctx context.Context) ([]map[string]interface{}, error) {
	areaTrees, err := s.areaRepo.AreaTrees(ctx)
	if err != nil {
		return nil, err
	}

	profit, err := s.profitRepo.GetProfitProvince(ctx)
	if err != nil {
		return nil, err
	}
	var (
		clueRadarProvince   bool
		clueRadarNationwide bool
		marketReport        bool
	)
	for _, item := range profit.GetProfits() {
		if item.GetProductCode() == "ClueRadarProvince" {
			clueRadarProvince = true
		} else if item.GetProductCode() == "ClueRadarNationwide" {
			clueRadarNationwide = true
		} else if item.GetProductCode() == "MarketReport" {
			marketReport = true
		}
	}

	if clueRadarProvince && (!clueRadarNationwide || !marketReport) {
		provinceCodeList := profit.GetProvinceCodeList()
		proftAreaTrees := make([]map[string]interface{}, 0)
		for _, area := range areaTrees {
			for _, provinceCode := range provinceCodeList {
				if area["item_code"] == provinceCode {
					proftAreaTrees = append(proftAreaTrees, area)
				}
			}
		}
		areaTrees = proftAreaTrees
	}

	return areaTrees, nil
}
